<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------

// 应用公共文件
function p($data)
{
    dump($data, true, '<pre>');
}

/**
 * 获取客户端IP地址
 * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
 * @param boolean $datadv 是否进行高级模式获取（有可能被伪装）
 * @return mixed
 */
function get_client_ip($type = 0, $datadv = false)
{
    $type = $type ? 1 : 0;
    static $ip = NULL;
    if ($ip !== NULL) {
        return $ip[$type];
    }
    if ($datadv) {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $datarr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos = array_search('unknown', $datarr);
            if (false !== $pos) {
                unset($datarr[$pos]);
            }
            $ip = trim($datarr[0]);
        } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip = $_SERVER['REMOTE_ADDR'];
        }
    } elseif (isset($_SERVER['REMOTE_ADDR'])) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    // IP地址合法验证
    $long = sprintf("%u", ip2long($ip));
    $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
    return $ip[$type];
}

/**
 * 获取 IP 地理位置
 * 淘新浪IP接口
 * @Return: array
 */
function GetIpLookup($ip = '')
{
    if (empty($ip)) {
        $ip = get_client_ip();
    }
    $res = @file_get_contents('http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js&ip=' . $ip);
    if (empty($res)) {
        return false;
    }
    $jsonMatches = array();
    preg_match('#\{.+?\}#', $res, $jsonMatches);
    if (!isset($jsonMatches[0])) {
        return false;
    }
    $json = json_decode($jsonMatches[0], true);
    if (isset($json['ret']) && $json['ret'] == 1) {
        $json['ip'] = $ip;
        unset($json['ret']);
    } else {
        return false;
    }
    return $json;
}

/**
 * access_token 生成函数
 * API用户注册时所用
 * @return string
 */
function create_token()
{
    $charid = strtoupper(md5(uniqid(mt_rand(), true)));
    $hyphen = chr(45);// "-"
    $token = substr($charid, 0, 8) . $hyphen
        . substr($charid, 8, 4) . $hyphen
        . substr($charid, 12, 4) . $hyphen
        . substr($charid, 16, 4) . $hyphen
        . substr($charid, 20, 12);
    return $token;
}

/**
 * 根据等级ID获取GID 是否为管理员 0 会员 1管理员 2 超级管理员
 * @param $id
 * @return mixed
 */
function getGidByLevel($id)
{
    $data = db('level')->field('gid')->find($id);
    return $data['gid'];
}

/**
 * @param $id
 * @param string $type
 * @return mixed|string
 */
function getLevel($id, $type = "")
{
    $data = db('level')->field('name')->find($id);
    $LevelName = $data['name'];
    if ($type) {
        if ($id > 10) {
            $LevelName = '<span style="color:#FF7200">' . $data["name"] . '</span>';
        }
    }
    return $LevelName;
}

//单纯判断是否是图片
function checkIsImage($filename)
{
    $alltypes = '.gif|.jpeg|.png|.bmp'; //定义检查的图片类型
    if (file_exists($filename)) {
        $result = getimagesize($filename);
        $ext = image_type_to_extension($result);
        return stripos($alltypes, $ext);
    } else {
        return false;
    }
}

/**
 * 时间转换函数
 * @param $time
 * @param $sfm 时分秒
 * @return bool|string
 */
function wordTime($time, $sfm = false)
{
    //$time_ = (int) substr($time, 0, 10);
    $int = time() - (int)strtotime($time);
    if ($int <= 2) {
        $str = sprintf('刚刚', $int);
    } elseif ($int < 60) {
        $str = sprintf('%d秒前', $int);
    } elseif ($int < 3600) {
        $str = sprintf('%d分钟前', floor($int / 60));
    } elseif ($int < 86400) {
        $str = sprintf('%d小时前', floor($int / 3600));
    } elseif ($int < 2592000) {
        $str = sprintf('%d天前', floor($int / 86400));
    } else {
        $str = date('Y-m-d', (int)strtotime($time));
        if ($sfm) $str = date('Y-m-d H:i:s', (int)strtotime($time));
    }
    return $str;
}

function str_rand($length = 8)
{
    // 密码字符集，可任意添加你需要的字符
    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $password = '';
    for ($i = 0; $i < $length; $i++) {
        // 这里提供两种字符获取方式
        // 第一种是使用 substr 截取$chars中的任意一位字符；
        // 第二种是取字符数组 $chars 的任意元素
        // $password .= substr($chars, mt_rand(0, strlen($chars) – 1), 1);
        $password .= $chars[mt_rand(0, strlen($chars) - 1)];
    }
    return $password;
}

/**
 * 时间格式转换
 * @param $data
 * @return bool|string
 */
function datetoYmd($data)
{
    return date('Y-m-d', strtotime($data));
}

/**
 * 获取这个主题的回复数量
 * @param $tid
 * @return int
 */
function getReplayCount($tid)
{
    $data = db('forum_reply')->where(['tid' => $tid, 'isdel' => 0])->count();
    return $data;
}

/**
 * 内容解析转换
 * @param $content
 */
function reply_replace($content)
{
    //replace(/a\([\s\S]+?\)\[[\s\S]*?\]/g, function(str){ //转义链接
    //var href = (str.match(/a\(([\s\S]+?)\)\[/)||[])[1];
    //var text = (str.match(/\)\[([\s\S]*?)\]/)||[])[1];
    //if(!href) return str;
    $content = preg_replace('/&(?!#?[a-zA-Z0-9]+;)/s', '&amp;', $content);
    $content = preg_replace('/</s', '&lt;', $content);
    $content = preg_replace('/>/s', '&gt;', $content);
    $content = preg_replace('/\'/s', '&#39;', $content);
    $content = preg_replace('/"/s', '&quot;', $content);
    $content = preg_replace('/\[pre\](.*?)\[\/pre\]/s', '<pre>${1}</pre>', $content);
    $content = preg_replace('/@(\S+)(\s+?|$)/s', '@<a href="javascript:;" class="fly-aite">${1}</a>${2}', $content);
    $content = preg_replace('/img\[([^\s]+?)\]/s', '<img src="${1}">', $content);
    //$content = preg_replace_callback('/face\[([^\s\[\]]+?)\]/s', 'getface', $content);
    $content = preg_replace('/a\([\s\S]+?\)\[(http:\/\/(\w+\.){2}\w+\/?\w+)]/s', '<a href="${1}" target="_blank" rel="nofollow">${1}</a>', $content);
    $content = preg_replace('/\n/s', '<br/>', $content);
    return $content;
}

/**
 * 内容解析转换
 * @param $content
 */
function reply_replace_ue_admin($content)
{
    //<img src="/uploads/attachment/201612/07/1481119352134637.jpg" title="1481119352134637.jpg" alt="0V3RDL22393L.jpg">
    $content = preg_replace('/@(\S+)(\s+?|$)/s', '@<a href="javascript:;" class="fly-aite">${1}</a>${2}', $content);
    $content = preg_replace('/img\[([^\s]+?)\]/s', '[图片]', $content);
    $content = preg_replace('/\[pre\](.*?)\[\/pre\]/s', '[代码]', $content);
    return $content;
}


/**
 * 用于百度编辑器回复内容
 * @param $content
 * @return mixed
 */
function reply_replace_face($content)
{
    $content = preg_replace('/@(\S+)(\s+?|$)/s', '@<a href="javascript:;" class="fly-aite">${1}</a>${2}', $content);
    return $content;
}


/**
 * PHP获取字符串中英文混合长度
 * @param $str string 字符串
 * @param $$charset string 编码
 * @return float
 */
function strLength($str, $charset = 'utf-8')
{
    if ($charset == 'utf-8') $str = iconv('utf-8', 'gb2312', $str);
    $num = strlen($str);
    $cnNum = 0;
    for ($i = 0; $i < $num; $i++) {
        if (ord(substr($str, $i + 1, 1)) > 127) {
            $cnNum++;
            $i++;
        }
    }
    $enNum = $num - ($cnNum * 2);
    $number = ($enNum / 2) + $cnNum;
    return ceil($number);
}

/**
 * 字符串截取，支持中文和其他编码
 *
 * @param string $str 需要转换的字符串
 * @param string $start 开始位置
 * @param string $length 截取长度
 * @param string $charset 编码格式
 * @param string $suffix 截断字符串后缀
 * @return string
 */
function substr_ext($str, $start = 0, $length, $charset = "utf-8", $suffix = "")
{
    if (function_exists("mb_substr")) {
        return mb_substr($str, $start, $length, $charset) . $suffix;
    } elseif (function_exists('iconv_substr')) {
        return iconv_substr($str, $start, $length, $charset) . $suffix;
    }
    $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
    $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
    $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
    $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
    preg_match_all($re[$charset], $str, $match);
    $slice = join("", array_slice($match[0], $start, $length));
    return $slice . $suffix;
}


/**
 * 根据UID返回头像
 * @param $uid
 * @return array|false|\PDOStatement|string|\think\Model
 */
function getByUserInfo($uid, $args)
{
    $data = db('user')->field($args)->find($uid);
    return $data[$args];
}

function getCageName($cate_id, $args)
{
    $data = db('category')->field($args)->find($cate_id);
    return $data[$args];
}

/**
 * 获取这个月的回复数量
 * @param $uid
 * @return int
 */
function getReplayUidCount($uid)
{
    $data = db('forum_reply')->where(['uid' => $uid, 'isdel' => 0])->whereTime('reply_time', 'month')->count();
    return $data;
}

/**
 * 首页最近热帖
 */
function Top_Posts()
{
    $data = db('forum')->field('id,title,view')->order('view desc')->limit(10)->select();
    return $data;
}

/**
 * 首页近期热议
 */
function nearList()
{
    $data = \think\Db::query('SELECT forum.id,forum.title,count(reply.tid) AS `view` FROM pe_forum AS forum LEFT JOIN pe_forum_reply AS reply ON reply.tid = forum.id
where forum.status=1 GROUP BY forum.id ORDER BY view DESC LIMIT 15');
    return $data;
}


/**
 * 将栏目重组
 * @param $data
 * @param $pid
 * @return array
 */
function get_arrayToTree($data, $pid)
{
    $tree = array();//每次都声明一个新数组用来放子元素
    foreach ($data as $v) {
        if ($v['pid'] == $pid) {//匹配子记录
            $v['children'] = get_arrayToTree($data, $v['id']); //递归获取子记录
            if ($v['children'] == null) {
                unset($v['children']);//如果子元素为空则unset()进行删除，说明已经到该分支的最后一个元素了（可选）
            }
            $tree[] = $v;//将记录存入新数组
        }
    }
    return $tree;//返回新数组
}


/**
 * @desc arraySort php二维数组排序 按照指定的key 对数组进行排序
 * @param array $arr 将要排序的数组
 * @param string $keys 指定排序的key
 * @param string $type 排序类型 asc | desc
 * @return array
 */
function arraySort($arr, $keys, $type = 'asc')
{
    $keysvalue = $new_array = array();
    foreach ($arr as $k => $v) {
        $keysvalue[$k] = $v[$keys];
    }
    $type == 'asc' ? asort($keysvalue) : arsort($keysvalue);
    reset($keysvalue);
    foreach ($keysvalue as $k => $v) {
        $new_array[$k] = $arr[$k];
    }
    return $new_array;
}

/**
 * 构建层级（树状）数组
 * @param array $array 要进行处理的一维数组，经过该函数处理后，该数组自动转为树状数组
 * @param string $pid 父级ID的字段名
 * @param string $child_key_name 子元素键名
 * @return array|bool
 */
function array2tree(&$array, $pid = 'pid', $child_key_name = 'children')
{
    $counter = array_children_count($array, $pid);
    if ($counter[0] == 0)
        return false;
    $tree = [];
    while (isset($counter[0]) && $counter[0] > 0) {
        $temp = array_shift($array);
        if (isset($counter[$temp['id']]) && $counter[$temp['id']] > 0) {
            array_push($array, $temp);
        } else {
            if ($temp[$pid] == 0) {
                $tree[] = $temp;
            } else {
                $array = array_child_append($array, $temp[$pid], $temp, $child_key_name);
            }
        }
        $counter = array_children_count($array, $pid);
    }

    return $tree;
}

/**
 * 子元素计数器
 * @param $array
 * @param $pid
 * @return array
 */
function array_children_count($array, $pid)
{
    $counter = [];
    foreach ($array as $item) {
        $count = isset($counter[$item[$pid]]) ? $counter[$item[$pid]] : 0;
        $count++;
        $counter[$item[$pid]] = $count;
    }

    return $counter;
}

/**
 * 把元素插入到对应的父元素$child_key_name字段
 * @param        $parent
 * @param        $pid
 * @param        $child
 * @param string $child_key_name 子元素键名
 * @return mixed
 */
function array_child_append($parent, $pid, $child, $child_key_name)
{
    foreach ($parent as &$item) {
        if ($item['id'] == $pid) {
            if (!isset($item[$child_key_name]))
                $item[$child_key_name] = [];
            $item['open'] = true;
            $item[$child_key_name][] = $child;
        }
    }
    return $parent;
}

/**
 * 数组层级缩进转换
 * @param array $array
 * @param int $pid
 * @param int $level
 * @return array
 */
function array2level($array, $pid = 0, $level = 1)
{
    static $list = [];
    foreach ($array as $v) {
        if ($v['pid'] == $pid) {
            $v['level'] = $level;
            $list[] = $v;
            array2level($array, $v['id'], $level + 1);
        }
    }
    return $list;
}

// 获取文件夹大小
function getDirSize($dir)
{
    $handle = opendir($dir);
    $sizeResult = 0;
    while (false !== ($FolderOrFile = readdir($handle))) {
        if ($FolderOrFile != "." && $FolderOrFile != "..") {
            if (is_dir("$dir/$FolderOrFile")) {
                $sizeResult += getDirSize("$dir/$FolderOrFile");
            } else {
                $sizeResult += filesize("$dir/$FolderOrFile");
            }
        }
    }
    closedir($handle);
    return $sizeResult;
}

// 单位自动转换函数
function getRealSize($size)
{
    $kb = 1024;         // Kilobyte
    $mb = 1024 * $kb;   // Megabyte
    $gb = 1024 * $mb;   // Gigabyte
    $tb = 1024 * $gb;   // Terabyte
    if ($size < $kb) {
        return $size . " B";
    } else if ($size < $mb) {
        return round($size / $kb, 2) . " KB";
    } else if ($size < $gb) {
        return round($size / $mb, 2) . " MB";
    } else if ($size < $tb) {
        return round($size / $gb, 2) . " GB";
    } else {
        return round($size / $tb, 2) . " TB";
    }
}

/**
 * 计算百分比函数
 * @param $num1
 * @param $num2
 * @return bool|string
 */
function getNum($num1, $num2)
{
    $num = false;
    if (is_numeric($num1) && is_numeric($num2)) {
        $num = round($num1 / $num2 * 100, 2) . "%";
        return $num;
    } else {
        return $num;
    }
}

/**
 * 验证手机号是否正确
 * @param number $mobile
 * @return bool;
 */
function isMobile($mobile)
{
    if (!is_numeric($mobile)) {
        return false;
    }
    return preg_match('#^13[\d]{9}$|^14[5,7]{1}\d{8}$|^15[^4]{1}\d{8}$|^17[0,6,7,8]{1}\d{8}$|^18[\d]{9}$#', $mobile) ? true : false;
}

/**
 * 循环删除目录和文件
 * @param string $dir_name
 * @return bool
 */
function delete_dir_file($dir_name)
{
    $result = false;
    if (is_dir($dir_name)) {
        if ($handle = opendir($dir_name)) {
            while (false !== ($item = readdir($handle))) {
                if ($item != '.' && $item != '..') {
                    if (is_dir($dir_name . DS . $item)) {
                        delete_dir_file($dir_name . DS . $item);
                    } else {
                        unlink($dir_name . DS . $item);
                    }
                }
            }
            closedir($handle);
            if (rmdir($dir_name)) {
                $result = true;
            }
        }
    }

    return $result;
}


/**
 *  authcode加密函数，Discuz!经典代码（带详解）
 *  ENCODE 加密 DECODE 解密
 * @param $string
 * @param string $operation
 * @param string $key
 * @param int $expiry
 * @return bool|string
 */
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
{
    // 动态密匙长度，相同的明文会生成不同密文就是依靠动态密匙
    $ckey_length = 4;
    // 密匙
    $key = md5($key ? $key : config('auth_key'));
    // 密匙a会参与加解密
    $keya = md5(substr($key, 0, 16));
    // 密匙b会用来做数据完整性验证
    $keyb = md5(substr($key, 16, 16));
    // 密匙c用于变化生成的密文
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length) :
        substr(md5(microtime()), -$ckey_length)) : '';
    // 参与运算的密匙
    $cryptkey = $keya . md5($keya . $keyc);
    $key_length = strlen($cryptkey);
    // 明文，前10位用来保存时间戳，解密时验证数据有效性，10到26位用来保存$keyb(密匙b)，
//解密时会通过这个密匙验证数据完整性
    // 如果是解码的话，会从第$ckey_length位开始，因为密文前$ckey_length位保存 动态密匙，以保证解密正确
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) :
        sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string;
    $string_length = strlen($string);
    $result = '';
    $box = range(0, 255);
    $rndkey = array();
    // 产生密匙簿
    for ($i = 0; $i <= 255; $i++) {
        $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }
    // 用固定的算法，打乱密匙簿，增加随机性，好像很复杂，实际上对并不会增加密文的强度
    for ($j = $i = 0; $i < 256; $i++) {
        $j = ($j + $box[$i] + $rndkey[$i]) % 256;
        $tmp = $box[$i];
        $box[$i] = $box[$j];
        $box[$j] = $tmp;
    }
    // 核心加解密部分
    for ($a = $j = $i = 0; $i < $string_length; $i++) {
        $a = ($a + 1) % 256;
        $j = ($j + $box[$a]) % 256;
        $tmp = $box[$a];
        $box[$a] = $box[$j];
        $box[$j] = $tmp;
        // 从密匙簿得出密匙进行异或，再转成字符
        $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }
    if ($operation == 'DECODE') {
        // 验证数据有效性，请看未加密明文的格式
        if ((substr($result, 0, 10) == 0 || substr($result, 0, 10) - time() > 0) &&
            substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)
        ) {
            return substr($result, 26);
        } else {
            return '';
        }
    } else {
        // 把动态密匙保存在密文里，这也是为什么同样的明文，生产不同密文后能解密的原因
        // 因为加密后的密文可能是一些特殊字符，复制过程可能会丢失，所以用base64编码
        return $keyc . str_replace('=', '', base64_encode($result));
    }
}